/**
 * Copyright 2006-2015 handu.com
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.iepacj.common.utils;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class IPUtils {

    private static List<String> unixIpList;

    /**
     * 获取内网ip
     * @return  内网ip地址
     */
    public static String localIP() {
       return getIp(true);
    }

    /**
     *
     * 根据系统的类型获取本服务器的ip地址--公网ip
     *
     * InetAddress inet = InetAddress.getLocalHost();
     * 但是上述代码在Linux下返回127.0.0.1。
     * 主要是在linux下返回的是/etc/hosts中配置的localhost的ip地址，
     * 而不是网卡的绑定地址。后来改用网卡的绑定地址，可以取到本机的ip地址
     */
    public static String netIP() {
        return getIp(false);
    }

    private static String getIp(boolean isLocal) {
        if (!isUnix()) {
            return getWindowIP();
        }
        if (unixIpList == null || unixIpList.size() == 0) {
            unixIpList = getUnixIPList();
        }
        if (unixIpList.size() == 0) {
            return "";
        }
        for (String ip : unixIpList) {
            if (isLocal && isInnerIP(ip)) {
                return ip;
            }
            if (!isLocal && !isInnerIP(ip)) {
                return ip;
            }
        }
        return unixIpList.get(0);
    }

    private static boolean isUnix() {
        String osName = System.getProperty("os.name");
        return osName.toLowerCase().indexOf("windows") != 0;
    }

    private static List<String> getUnixIPList() {
        List<String> ipList = new ArrayList<>();
        try {
            Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
            while (nets.hasMoreElements()) {
                NetworkInterface niFace = nets.nextElement();
                if (niFace.isLoopback() || niFace.isVirtual() || !niFace.isUp()) {
                    continue;
                }
                Enumeration<InetAddress> addres = niFace.getInetAddresses();
                while (addres.hasMoreElements()) {
                    InetAddress inetAddress = addres.nextElement();
                    String hostAddr = inetAddress.getHostAddress();
                    if (!hostAddr.contains(":")) {
                        ipList.add(hostAddr);
                    }
                }
            }
            return ipList;
        } catch (SocketException e) {
            e.printStackTrace();
            return ipList;
        }
    }

    private static String getWindowIP() {
        try {
            InetAddress localHost = InetAddress.getLocalHost();
            return localHost.getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
            return "";
        }
    }

    private static boolean isInnerIP(String ipAddress) {
        long ipNum = getIpNum(ipAddress);
        /**
         * 私有IP：A类 10.0.0.0-10.255.255.255 B类 172.16.0.0-172.31.255.255 C类
         * 192.168.0.0-192.168.255.255 当然，还有127这个网段是环回地址
         **/
        long aBegin = getIpNum("10.0.0.0");
        long aEnd = getIpNum("10.255.255.255");
        long bBegin = getIpNum("172.16.0.0");
        long bEnd = getIpNum("172.31.255.255");
        long cBegin = getIpNum("192.168.0.0");
        long cEnd = getIpNum("192.168.255.255");
        return isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd)
                || isInner(ipNum, cBegin, cEnd) || ipAddress.equals("127.0.0.1");
    }

    private static long getIpNum(String ipAddress) {
        String[] ip = ipAddress.split("\\.");
        long a = Integer.parseInt(ip[0]);
        long b = Integer.parseInt(ip[1]);
        long c = Integer.parseInt(ip[2]);
        long d = Integer.parseInt(ip[3]);
        return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
    }

    private static boolean isInner(long userIp, long begin, long end) {
        return (userIp >= begin) && (userIp <= end);
    }

    public static void main(String[] args) {
        System.out.println(isUnix());
        System.out.println("内网ip => " + localIP());
        System.out.println("外网ip => " + netIP());
    }

}
